#!/usr/bin/python
"""
TestState2Str.py
Derek O Sullivan & Paddy Burke
Unit Test module for the state2str method in ChessBoard.py

"""
import unittest
from ChessBoard import *

class testState2str(unittest.TestCase):
  _STATE_LEN = 72

  # Game result reason values                                                
  GR_INVALID_MOVE = 1
  GR_INVALID_COLOR = 2
  GR_INVALID_FROM_LOCATION = 3
  GR_INVALID_TO_LOCATION = 4
  GR_MUST_SET_PROMOTION = 5
  GR_GAME_IS_OVER = 6
  GR_AMBIGUOUS_MOVE = 7

  def setUp(self):
    """ 
    SetUp data used for tests
    """
    self.testBoard = ChessBoard()
    self.testBoard.resetBoard()
   
  def testInit(self):
    """
    Test is not none 
    """
    self.assertTrue(self.testBoard is not None)

  def testBasic(self):
    """
    Basic test to check output from state2str 
    """
    a = self.testBoard.state2str()
    self.assertNotEqual(a, '')
    print a

  def testMovePiece(self):
    """
    This tests that the state string has changed after a move
    and
    validates that the state string has been updated correctly
    """
    a = self.testBoard.state2str()
    self.testBoard.movePawn((1,6),(1,5))

    b = self.testBoard.state2str()
    #print a
    #print b
    #for i in range(len(b)):
      #print b[i] + " - " + str(i)

    self.assertTrue(a != b)
    self.assertEqual(a[0:40], b[0:40])
    self.assertEqual('P', b[41])
    self.assertEqual(a[42:48], b[42:48])
    self.assertEqual('.', b[49])
    self.assertEqual(a[50:], b[50:])

  def testChangeFlagWhiteKingCastle(self):
    """
    Tests that the flag for white king castle is updated
    correctly in state string when the state changes 
    """
    self.assertTrue(self.testBoard._white_king_castle)
    self.testBoard._white_king_castle = False
    self.assertFlagValue(0, -9)

  def testChangeFlagWhiteQueenCastle(self):
    """
    Tests that the flag for white queen castle is updated 
    correctly in state string when the state changes    
    """
    self.assertTrue(self.testBoard._white_queen_castle)
    self.testBoard._white_queen_castle = False
    self.assertFlagValue(0, -8)
    
  def testChangeFlagBlackKingCastle(self):
    """
    Tests that the flag for black king castle is updated 
    correctly in state string when the state changes
    """
    self.assertTrue(self.testBoard._black_king_castle)
    self.testBoard._black_king_castle = False
    self.assertFlagValue(0, -7)

  def testChangeFlagBlackQueenCastle(self):
    """
    Tests that the flag for Black king castle is updated 
    correctly in state string when the state changes    
    """
    self.assertTrue(self.testBoard._black_queen_castle)
    self.testBoard._black_queen_castle = False
    self.assertFlagValue(0, -6)    

  def testColorChange(self):
    """
    Tests that the Flag for Color Change gets updated 
    in the state string to reflect the correct state after 
    a move has been made
    """
    self.testBoard._turn = ChessConsts.WHITE
    state = self.testBoard.state2str()
    self.assertEqual(str(0), state[64])
    self.assertLength()

    self.testBoard._turn = ChessConsts.BLACK  
    state = self.testBoard.state2str()
    self.assertEqual(str(1), state[64])
    self.assertLength()    

    self.testBoard._turn = ChessConsts.NOCOLOR    
    self.assertLength()
    
  def testEnPassantNone(self):
    """
    Test that will throw an exception if EnPassant flag 
    is set to none, boundary value analysis
    """
    self.assertEqual(0, self.testBoard._ep[0])
    self.assertEqual(0, self.testBoard._ep[1])
    self.testBoard._ep = None
    self.assertRaises(TypeError, self.testBoard.state2str)

  def testEnPassantChange(self):
    """
    Tests 
    """
    self.assertEqual(0, self.testBoard._ep[0])
    self.assertEqual(0, self.testBoard._ep[1])
    a = self.testBoard.state2str()
    self.testBoard._ep[0] = 6
    self.testBoard._ep[1] = 3
    b = self.testBoard.state2str()
    self.assertNotEqual(a, b)
    self.assertEqual(str(6), b[-5])
    self.assertEqual(str(3), b[-4])

  def testEnPassantOutOfRange(self):
    """
    Tests that En passant co-ordinates should not exceed 7,7
    """
    a = self.testBoard.state2str()
    self.testBoard._ep[0] = 4
    self.testBoard._ep[1] = 13
    b = self.testBoard.state2str()
    self.assertNotEqual(a, b)
    self.assertLength()

  def testFiftyInRange(self):
    """
    Tests the value of the fifty move rule flag in the state 
    string is correct when the value is in range 

    """
    self.testBoard._fifty = 20
    state = self.testBoard.state2str()
    self.assertEqual('20', state.split(':')[1])
    self.assertLength()

  def testFiftyGreaterThanRange(self):
    """
    Tests the value of the fifty move rule flag in the state 
    string is correct when the value is greater than upper boundary 
    """
    self.testBoard._fifty = 105
    state = self.testBoard.state2str()
    print "greater before split " + state
    print "after split " + (state.split(':')[1])
    self.assertEqual('*', state.split(':')[1])
    self.assertLength()

  def testFiftyLowerThanRange(self):
    """
    Tests the value of the fifty move rule flag in the state 
    string is correct when the value is less than the lower boundary 
    """
    self.testBoard._fifty = -30
    state = self.testBoard.state2str()
    self.assertEqual('*', state.split(':')[1])
    self.assertLength()

  def assertFlagValue(self, expected, position):
    val = self.testBoard.state2str()
    self.assertEqual(str(expected), val[position])

  def assertLength(self):
    s = self.testBoard.state2str()
    parts = s.split(':')
    self.assertEqual(2, len(parts))

    self.assertEqual(self._STATE_LEN, len(parts[0]))

    if parts[1] is not '*':
      fiftyVal = int(parts[1])
      self.assertTrue(fiftyVal >= 0)
      self.assertTrue(fiftyVal <= 100)
    
if __name__ == "__main__":
  unittest.main()

